<?php
// +----------------------------------------------------------------------
// |ZBPHP[基于ThinkPHP5.1开发]
// +----------------------------------------------------------------------
// | Copyright (c) 2016-2019 http://www.benbenwangluo.com
// +----------------------------------------------------------------------
// | Author 似水星辰 [ 2630481389@qq.com ]
// +----------------------------------------------------------------------
// | 中犇软件 技术六部 出品
// +----------------------------------------------------------------------

namespace app\common\model;

use Firebase\JWT\JWT;
use service\ApiReturn;
use think\Validate;
use think\facade\Request;
use app\user\model\User;

/**
 * Api请求统一调度
 * @author 似水星辰 [ 2630481389@qq.com ]
 * @after 晓风<215628355@qq.com> 2020年10月14日09:14:13
 */
class Api
{
    //接口信息
    public static $apiInfo = null;
    //接口参数
    public static $param = null;
    //用户信息
    public static $user = [];

    /**
     * 头部 公共参数
     * @param array $header 头部参数数组
     * @param string $alg 声明签名算法为SHA256
     * @return string $typ 声明类型为jwt
     */
    private static $header = [
        'alg' => 'HS256', //生成signature的算法 //声明签名算法为SHA256
        'typ' => 'JWT'  //声明类型为jwt
    ];

    // 初始化处理
    public static function init($hash)
    {
        $apiInfo = Apilist::getCacheInfo($hash);
        
        if (empty($apiInfo)) {
            return ApiReturn::r('-1'); //hash参数无效
        }

        self::$apiInfo = $apiInfo;
        if ($apiInfo['status'] < 1) {
            return ApiReturn::r('-230', '', '接口已禁用'); // 参数错误
        }
	
        $header = Request::header();
        $data = self::getFormData($apiInfo["method"]);        
        $check = self::checkData($hash, $data);
        if($check){
            return $check;
        }  
        
//	// MOCK数据模式下开始模拟数据
//        if($apiInfo['isTest'] == -1){                  
//            return 66;
//        }
        //验证签名
        if ($apiInfo['checkSign'] && $apiInfo['isTest']) {
            $ret = self::checkSign($header, $data);
            if ($ret) {
                return $ret;
            }
        }
        //验证TOKEN
        if ($apiInfo['needLogin'] && !$header['user-token']) {       
            return ApiReturn::r('-201', [], '您还没有登录，请先登录！');
        }
        //有TOKEN就获取user    
        if ($header['user-token']) {
            $ret = self::checkUserToken($header['user-token']);
            if ($apiInfo['needLogin'] &&  $ret) {
                return $ret;
            }
        }    
        return 0;
    }

    /**
     * 验签SIGN
     * @param $header 用户提交的header
     * @param $formdata 用户提交的表单数据
     * @return int|json
     * @author 似水星辰 [ 2630481389@qq.com ]
     */
    public static function checkSign($header, $formdata)
    {
        $sign['appid'] = $header['appid'] ?? null;
        $sign['signaturenonce'] =  $header['signaturenonce'] ?? null;
        $sign['timestamp'] = $header['timestamp'] ?? null;
        if(!$sign['appid']){
            return ApiReturn::r('-101', '', '缺少AppId参数');
        }
        if(!$sign['signaturenonce']){
            return ApiReturn::r('-102', '', '缺少SignatureNonce参数');
        }
        if(!$header['signature']){
            return ApiReturn::r('-103', '', '缺少Signature参数');
        }
        if(!$sign['timestamp']){
            return ApiReturn::r('-104', '', '缺少Timestamp参数');
        }

        $time = time();
        $max = $sign['timestamp'] - 60;
        if($max > $time ){
            return ApiReturn::r('-105', '', '请求时间不正确');
        }

        $min = $sign['timestamp'] + 60;
        if($min < $time ){
            return ApiReturn::r('-106', '', '请求时间已过期');
        }

        $app = Apiapp::getCache($sign['appid']);
        if(!$app || !$app['app_secret']){
            return ApiReturn::r('-107', '', 'APPID未授权');
        } 
        $sign["appsecret"] = $app['app_secret'] ;        
        $sign =array_merge($sign, $formdata);
        ksort($sign);
        $string = [];
        foreach($sign as $key=>$val){
            $string[] = $key . '=' . $val;
        }
        $signdata = implode("&",$string);

        $checkSign = sha1($signdata);

        if ($checkSign === $header['signature']) {
            //验证通过返回0即可,我偷下懒
            return 0;
        }

	unset($sign['appsecret']);
        return ApiReturn::r('-108', $sign, '签名不正确');
    }

    

    /**
     * 获得用户提交的参数
     * @author 晓风<215628355@qq.com>
     * @param int $method
     * @return type
     */
    protected static function getFormData($method = 0){
        $request = Request::instance();
        if ($method == 1) { // post获取数据
            return $request->post();
        } 
        if ($method == 2) { // get获取数据
            return $request->get();
        }
        $_method = strtoupper(request()->method()); // 用当前的请求方式 获取数据
        switch ($_method) {
            case 'GET':
                return $request->get();                
            case 'POST':
                return $request->post();         
            case 'DELETE':
                return $request->delete();       
            case 'PUT':
                return $request->put();       
            default :              
                break;
        }
        return [];
    }
    /**
     * 验证参数并存储data
     * @param string $hash
     * @param array $data
     * @return int
     */
    protected static function checkData($hash , $data){
        $rule = ApiFields::getCacheFields($hash, 0); //获取数据库的 请求字段
        $newRule = ApiFields::cacheBuildValidateRule($rule);
        if ($newRule) {
            $validate = new Validate($newRule);
            if (!$validate->check($data)) {  //验证
                return ApiReturn::r('-900', [], $validate->getError()); // 参数错误
            }
        }
        $newData = [];
        foreach ($rule as $item) {
            if ($data[$item['fieldName']] == '') {
                if($item['default'] != ''){
                    $newData[$item['fieldName']] = $item['default'];
                }
            } else {
                $newData[$item['fieldName']] = $data[$item['fieldName']];
            }
        }
        self::$param = $newData;
        return 0;
    }
    
    /**
     * 获取会员信息
     * @author 晓风<215628355@qq.com>
     * @param int $id
     * @param string $cache
     * @return mixed
     */
    public static function getUserInfo($id,$cache = 3600){
        return  User::alias('u')
                ->join('user_info i', 'u.id=i.user_id', 'left')
                ->where('u.id', $id)
                ->cache('userinfo_' . $id, $cache)
                ->field('i.*')
                ->field('u.password,i.user_id,i.update_time', true)
                ->find();  
    }
     /**
     * 清除会员缓存
     * @author 晓风<215628355@qq.com>
     * @param int $id
     */
    public static function clearUserCache($id){
       cache('userinfo_' . $id,null);
    }


     /**
     * 验证User-token 并存入user
     * @author 晓风<215628355@qq.com>
     * @param string $userToken
     * @return mixed
     */
    protected static function checkUserToken(string $userToken){             
   
        try{     
            $uid =  ApiApptoken::checkToken($userToken);
        }catch(\Exception $e){
            return ApiReturn::r('-202', [], $e->getMessage());
        }  
        $userinfo = self::getUserInfo($uid);
        if(!$userinfo){
             return ApiReturn::r('-203', [], '登录信息失效，请重新登录');
        }
        if($userinfo["status"] != 1){
            return ApiReturn::r('-203', [], '你的账户已禁用');
        }
        if($userinfo["is_delete"] == 1){
            return ApiReturn::r('-203', [], '你的账户已注销');
        }
        self::$user = $userinfo;
        return 0;
    }
    /**
     * 对外方法，获得user里的参数
     * @author 晓风<215628355@qq.com>
     * @param string $field
     * @return array|string
     */
    public static function getUser($field = ""){
        return $field ? (self::$user[$field] ?? null) : self::$user;
    }
    
    
    /** 
     * 创建 token
     * @param array $uid 必填 会员id
     * @param integer $exp_time 必填 token过期时间 单位:秒 例子：7200=2小时
     * @return string
     */
    public static function createToken($uid, $exp_time = 0, $scopes = "")
    {                 
         if(!$exp_time){
             $exp_time = 86400 * 30;
         }
         return  ApiApptoken::refreshToken($uid, $exp_time);
    }
   
    /**
     * 根据TOKEN获取用户信息
     * @author 似水星辰 [ 2630481389@qq.com ]
     * @created 2020/9/16 20:59
     */
    public static function get_user_info()
    {
        if(self::$user){
            return self::$user;
        }
        $header = Request::header();
        if(!$header['user-token']){
            return null;
        }
        try{     
            $uid =  ApiApptoken::checkToken($header['user-token']);
        }catch(\Exception $e){
            return null;
        }     
        $user = self::getUserInfo($uid);
        if($user){
            $user['head_img'] = get_file_url($user['head_img']);
            self::$user = $user; 
        }        
        return self::$user;       
    }
}
